package org.learnaholic.application.model;

import java.util.Date;
import java.util.Iterator;

public class KnowledgeFactory
{

	/** 2 hours */
	private static final long	first_decline_time = 1000 * 60 * 60 * 3;
	
	public static Knowledge getKnowledge(TestResultLog testResultLog)
	{
		Knowledge knowledge = Knowledge.UNTESTED;

		if(testResultLog.size() > 0)
		{
			TestResult lastResult = testResultLog.lastEntry().getValue();
			
			switch (lastResult)
			{
				case PARTIALLY_CORRECT:
					knowledge = Knowledge.PARTIALLY_KNOWN;
					break;
				case WRONG:
					knowledge = Knowledge.TOTALLY_UNKNOWN;
					break;
				case CORRECT:

					Date continuousSuccessEndDate = testResultLog.lastKey();
					Date continuousSuccessStartDate = continuousSuccessEndDate;
					boolean success = true;
					
					for (Iterator<Date> iterator = testResultLog.descendingKeySet().iterator(); iterator.hasNext() && success;)
					{
						Date date = iterator.next();
						success = testResultLog.get(date) == TestResult.CORRECT;
						if(testResultLog.get(date) == TestResult.CORRECT)
						{
							continuousSuccessStartDate = date;
						}	
					}
					knowledge = getKnowledge(continuousSuccessStartDate, continuousSuccessEndDate);
					
					break;

				default:
					break;
			}
			
		}
		
		return knowledge;
	}
	

	/**
	 * @param continuousSuccessStartDate
	 * @param continuousSuccessEndDate
	 * @return
	 */
	public static Knowledge getKnowledge(Date continuousSuccessStartDate, Date continuousSuccessEndDate)
	{
		Knowledge ret;
		long successDuration = continuousSuccessEndDate.getTime() - continuousSuccessStartDate.getTime();
		successDuration = Math.max(first_decline_time, successDuration);
		long nonTestedSince = (new Date().getTime() - continuousSuccessEndDate.getTime()) + 1;
		nonTestedSince = Math.max(1, nonTestedSince);
		double dRatio = Math.sqrt(nonTestedSince  / successDuration);
		byte ratio = (byte) Math.min(4, dRatio);
	
		switch (ratio)
		{
			case 0:
				ret = Knowledge.KNOWN_FORGOTTEN_LEVEL_0;
				break;
			case 1:
				ret = Knowledge.KNOWN_FORGOTTEN_LEVEL_1;
				break;
			case 2:
				ret = Knowledge.KNOWN_FORGOTTEN_LEVEL_2;
				break;
			case 3:
				ret = Knowledge.KNOWN_FORGOTTEN_LEVEL_3;
				break;
			default:
				ret = Knowledge.KNOWN_FORGOTTEN_LEVEL_4;
				break;
		}
		return ret;
	}
}
